home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1990,1991,1992 Chris and John Downey */
- #ifndef lint
- static char *sccsid = "@(#)windows.c 2.2 (Chris & John Downey) 8/28/92";
- #endif
-
- /***
-
- * program name:
- xvi
- * function:
- PD version of UNIX "vi" editor, with extensions.
- * module name:
- windows.c
- * module function:
- Window handling functions.
- * history:
- STEVIE - ST Editor for VI Enthusiasts, Version 3.10
- Originally by Tim Thompson (twitch!tjt)
- Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
- Heavily modified by Chris & John Downey
-
- ***/
-
- #include "xvi.h"
-
- #undef min
- #define min(a, b) (((a) < (b)) ? (a) : (b))
-
- static int nwindows = 0;
-
- static Xviwin *new_window P((Xviwin *, Xviwin *));
- static bool_t setup_window P((Xviwin *));
-
- Xviwin *
- init_window(vs)
- VirtScr *vs;
- {
- Xviwin *newwin;
- newwin = new_window((Xviwin *) NULL, (Xviwin *) NULL);
- if (newwin == NULL) {
- return(NULL);
- }
-
- newwin->w_vs = vs;
- newwin->w_nrows = (*vs->v_rows)(vs);
- newwin->w_ncols = (*vs->v_cols)(vs);
-
- /*
- * Initialise screen stuff.
- */
- init_screen(newwin);
-
- newwin->w_winpos = 0;
- newwin->w_cmdline = Rows - 1;
- return(newwin);
- }
-
- /*
- * Split the given window in half, placing a new empty
- * window in the bottom section and resizing the old one
- * in the top half.
- */
- Xviwin *
- split_window(oldwin)
- Xviwin *oldwin;
- {
- Xviwin *newwin;
-
- /*
- * Make sure there are enough rows for the new window.
- * This does not obey the minrows parameter, because
- * the point is to have enough space to actually display
- * a window, not just to have a zero-size one.
- */
- if (oldwin->w_nrows < (MINROWS * 2))
- return(NULL);
-
- newwin = new_window(oldwin, oldwin->w_next);
- if (newwin == NULL) {
- return(NULL);
- }
-
- newwin->w_vs = oldwin->w_vs;
-
- /*
- * Calculate size and position of new and old windows.
- */
- newwin->w_nrows = oldwin->w_nrows / 2;
- newwin->w_cmdline = oldwin->w_cmdline;
- newwin->w_winpos = (newwin->w_cmdline - newwin->w_nrows) + 1;
-
- oldwin->w_nrows -= newwin->w_nrows;
- oldwin->w_cmdline = newwin->w_winpos - 1;
-
- newwin->w_ncols = oldwin->w_ncols;
-
- return(newwin);
- }
-
- /*
- * Delete the given window.
- */
- void
- free_window(window)
- Xviwin *window;
- {
- if (window == NULL || nwindows < 1)
- return;
-
- if (window->w_next != NULL) {
- window->w_next->w_last = window->w_last;
- }
- if (window->w_last != NULL) {
- window->w_last->w_next = window->w_next;
- }
- nwindows -= 1;
-
- window->w_buffer->b_nwindows -= 1;
-
- free((char *) window->w_cursor);
- flexdelete(&window->w_statusline);
- free((char *) window);
- }
-
- /*
- * Allocate a new window.
- */
- static Xviwin *
- new_window(last, next)
- Xviwin *last, *next;
- {
- Xviwin *newwin;
-
- newwin = (Xviwin *) malloc(sizeof(Xviwin));
- if (newwin == NULL) {
- return(NULL);
- }
-
- if (setup_window(newwin) == FALSE) {
- free((char *) newwin);
- return(NULL);
- }
-
- /*
- * Link the window into the list.
- */
- if (last != NULL) {
- last->w_next = newwin;
- }
- if (next != NULL) {
- next->w_last = newwin;
- }
- newwin->w_last = last;
- newwin->w_next = next;
- nwindows += 1;
-
- return(newwin);
- }
-
- /*
- * Set up and allocate data structures for the given window,
- * assumed to contain a valid pointer to a buffer.
- *
- * This routine should be called after setup_buffer().
- */
- static bool_t
- setup_window(w)
- Xviwin *w;
- {
- /*
- * Allocate space for the status line.
- */
- flexnew(&w->w_statusline);
-
- /*
- * Allocate a Posn structure for the cursor.
- */
- w->w_cursor = (Posn *) malloc(sizeof(Posn));
- if (w->w_cursor == NULL) {
- return(FALSE);
- }
-
- return(TRUE);
- }
-
- void
- map_window_onto_buffer(w, b)
- Xviwin *w;
- Buffer *b;
- {
- /*
- * Connect the two together.
- */
- w->w_buffer = b;
- b->b_nwindows += 1;
-
- /*
- * Put the cursor and the screen in the right place.
- */
- move_cursor(w, b->b_file, 0);
- w->w_topline = b->b_file;
- w->w_botline = b->b_lastline;
-
- /*
- * Miscellany.
- */
- w->w_row = w->w_col = 0;
- w->w_virtcol = 0;
- w->w_curswant = 0;
- w->w_set_want_col = FALSE;
- w->w_curs_new = TRUE;
- }
-
- /*
- * Unmap the given window from its buffer.
- * We don't need to do much here, on the assumption that the
- * calling code is going to do a map_window_onto_buffer()
- * immediately afterwards; the vital thing is to decrement
- * the window reference count.
- */
- void
- unmap_window(w)
- Xviwin *w;
- {
- w->w_buffer->b_nwindows -= 1;
-
- w->w_cursor->p_line = NULL;
- w->w_topline = NULL;
- w->w_botline = NULL;
- }
-
- /*
- * Given a window, find the "next" one in the list.
- */
- Xviwin *
- next_window(window)
- Xviwin *window;
- {
- if (window == NULL) {
- return(NULL);
- } else if (window->w_next != NULL) {
- return(window->w_next);
- } else {
- Xviwin *tmp;
-
- /*
- * No next window; go to start of list.
- */
- for (tmp = window; tmp->w_last != NULL; tmp = tmp->w_last)
- ;
- return(tmp);
- }
- }
-
- /*
- * Find the next window onto the buffer with the given filename,
- * starting at the current one; if there isn't one, or if it is
- * too small to move into, return NULL.
- */
- Xviwin *
- find_window(window, filename)
- Xviwin *window;
- char *filename;
- {
- Xviwin *wp;
- char *f;
-
- if (window != NULL && filename != NULL) {
- wp = window;
- do {
- f = wp->w_buffer->b_filename;
- if (f != NULL && strcmp(filename, f) == 0) {
- return(wp);
- }
- wp = next_window(wp);
- } while (wp != window);
- }
-
- return(NULL);
- }
-
- /*
- * Grow or shrink the given buffer window by "nlines" lines.
- * We prefer to move the bottom of the window, and will only
- * move the top when there is no room for manoeuvre below
- * the current one - i.e. any windows are at minimum size.
- */
- void
- resize_window(window, nlines)
- Xviwin *window;
- int nlines;
- {
- unsigned savecho;
-
- if (nlines == 0 || nwindows == 1) {
- /*
- * Nothing to do.
- */
- return;
- }
-
- savecho = echo;
-
- if (nlines < 0) {
- int spare; /* num spare lines in this window */
-
- nlines = - nlines;
-
- /*
- * The current window must always contain 2 rows,
- * so that the cursor has somewhere to go.
- */
- spare = window->w_nrows - MINROWS;
-
- /*
- * If the window is already as small as it
- * can get, don't bother to do anything.
- */
- if (spare <= 0)
- return;
-
- /*
- * Don't allow any screen updating until we've
- * finished moving things around.
- */
- echo &= ~e_CHARUPDATE;
-
- /*
- * First shrink the current window up from the bottom.
- *
- * move_sline()'s return value should be negative or 0
- * in this case.
- */
- nlines += move_sline(window, - min(spare, nlines));
-
- /*
- * If that wasn't enough, grow the window above us
- * by the appropriate number of lines.
- */
- if (nlines > 0) {
- (void) move_sline(window->w_last, nlines);
- }
- } else {
- /*
- * Don't allow any screen updating until we've
- * finished moving things around.
- */
- echo &= ~e_CHARUPDATE;
-
- /*
- * Expand window.
- */
- nlines -= move_sline(window, nlines);
- if (nlines > 0) {
- (void) move_sline(window->w_last, -nlines);
- }
- }
-
- /*
- * Update screen. Note that status lines have
- * already been updated by move_sline().
- *
- * This still needs a lot more optimization.
- */
- echo = savecho;
- update_all();
- }
-
- /*
- * Adjust the boundary between two adjacent windows by moving the status line
- * up or down, updating parameters for both windows as appropriate.
- *
- * Note that this can shrink the window to size 0.
- */
- int
- move_sline(wp, nlines)
- Xviwin *wp; /* window whose status line we have to move */
- int nlines; /*
- * number of lines to move (negative for
- * upward moves, positive for downwards)
- */
- {
- Xviwin *nextwin;
-
- if (wp == NULL || (nextwin = wp->w_next) == NULL) {
- return(0);
- }
-
- if (nlines < 0) { /* move upwards */
- int amount;
- int spare;
-
- amount = -nlines;
- spare = wp->w_nrows - Pn(P_minrows);
-
- if (amount > spare && wp->w_last != NULL) {
- /*
- * Not enough space: call move_sline() recursively
- * for previous line; note that the second parameter
- * should be negative.
- */
- (void) move_sline(wp->w_last, spare - amount);
- spare = wp->w_nrows - Pn(P_minrows);
- }
- if (amount > spare)
- amount = spare;
- if (amount != 0) {
- wp->w_nrows -= amount;
- wp->w_cmdline -= amount;
- nextwin->w_winpos -= amount;
- nextwin->w_nrows += amount;
- (void) shiftdown(nextwin, (unsigned) amount);
- if (wp->w_nrows > 0) {
- show_file_info(wp);
- }
- }
- nlines = -amount; /* return value */
- } else { /* move downwards */
- int spare;
-
- spare = nextwin->w_nrows - Pn(P_minrows);
-
- if (nlines > spare) {
- /*
- * Not enough space: call move_sline()
- * recursively for next line.
- */
- (void) move_sline(nextwin, nlines - spare);
- spare = nextwin->w_nrows - Pn(P_minrows);
- }
- if (nlines > spare)
- nlines = spare;
- if (nlines != 0) {
- wp->w_nrows += nlines;
- wp->w_cmdline += nlines;
- nextwin->w_winpos += nlines;
- nextwin->w_nrows -= nlines;
- (void) shiftup(nextwin, (unsigned) nlines);
- if (wp->w_nrows > 0) {
- show_file_info(wp);
- }
- }
- }
- return(nlines);
- }
-
- /*
- * Update all windows associated with the given buffer.
- */
- void
- update_buffer(buffer)
- Buffer *buffer;
- {
- Xviwin *w;
-
- w = curwin; /* as good a place as any to start */
- do {
- if (w->w_buffer == buffer) {
- update_window(w);
- }
- w = next_window(w);
- } while (w != curwin);
- }
-
- bool_t
- can_split()
- {
- return(nwindows < Pn(P_autosplit));
- }
-